"#include \"FullScreenTriangleVSOutput.fxh\"\n"
"#include \"GLTF_PBR_PrecomputeCommon.fxh\"\n"
"\n"
"#define NUM_SAMPLES 512u\n"
"\n"
"float2 IntegrateBRDF( float Roughness, float NoV, uint NumSamples )\n"
"{\n"
"    float3 V;\n"
"    V.x = sqrt( 1.0 - NoV * NoV ); // sin\n"
"    V.y = 0.0;\n"
"    V.z = NoV; // cos\n"
"    const float3 N = float3(0.0, 0.0, 1.0);\n"
"    float A = 0.0;\n"
"    float B = 0.0;\n"
"    for( uint i = 0u; i < NumSamples; i++ )\n"
"    {\n"
"        float2 Xi = Hammersley2D( i, NumSamples );\n"
"        float3 H = ImportanceSampleGGX( Xi, Roughness, N );\n"
"        float3 L = 2.0 * dot( V, H ) * H - V;\n"
"        float NoL = saturate( L.z );\n"
"        float NoH = saturate( H.z );\n"
"        float VoH = saturate( dot( V, H ) );\n"
"        if( NoL > 0.0 )\n"
"        {\n"
"            // https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\n"
"            // Also see eq. 92 in  https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights\n"
"            // Note that VoH / (NormalDistribution_GGX(H,Roughness) * NoH) term comes from importance sampling\n"
"            float G_Vis = 4.0 * SmithGGXVisibilityCorrelated( NoL, NoV, Roughness ) * VoH * NoL / NoH;\n"
"            float Fc = pow( 1.0 - VoH, 5.0 );\n"
"            A += (1.0 - Fc) * G_Vis;\n"
"            B += Fc * G_Vis;\n"
"        }\n"
"    }\n"
"    return float2( A, B ) / float(NumSamples);\n"
"}\n"
"\n"
"void PrecomputeBRDF_PS(FullScreenTriangleVSOutput VSOut,\n"
"                       out float2 f2BRDF_LUT : SV_Target)\n"
"{\n"
"    float2 UV = NormalizedDeviceXYToTexUV(VSOut.f2NormalizedXY);\n"
"    float NdotV           = UV.x;\n"
"    float linearRoughness = UV.y;\n"
"    f2BRDF_LUT = IntegrateBRDF(linearRoughness, NdotV, NUM_SAMPLES);\n"
"}\n"
